////////////////////////////////////////////////
// DESCRIPTION:
//    Custom Emulator extensions
//
// Legal Notices:
//   Copyright (c) 2008, Telliam Consulting, LLC.
//   All rights reserved.
//
//   Redistribution and use in source and binary forms, with or without modification,
//   are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice, this list
//     of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice, this
//     list of conditions and the following disclaimer in the documentation and/or other
//     materials provided with the distribution.
//   * Neither the name of Telliam Consulting nor the names of its contributors may be
//     used to endorse or promote products derived from this software without specific
//     prior written permission.
//
//   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
//   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
//   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
//   SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
//   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
//   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
//   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
//   DAMAGE. 
//
using System;
using System.IO;
using System.Xml;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.ComponentModel;
using Microsoft.SPOT.Hardware;
using System.Collections.Generic;
using Microsoft.SPOT.Emulator.Gpio;

namespace FusionWare.SPOT.EmulatorComponents
{
    /// <summary>Provides a central Component for a complete Tahoe platform emulation</summary>
    /// <remarks>
    /// This custom emulator allows for simpler UI creatin by providing a single form for
    /// all components to work from and standarizing the process of binding controls to 
    /// the emulator components they represent.
    /// </remarks>
    public abstract class CustomEmulator : Microsoft.SPOT.Emulator.Emulator
    {
        /// <summary>Creates a new Custom Emulator</summary>
        protected CustomEmulator()
        {
        }

        /// <summary>Main Form for the emulation</summary>
        /// <remarks>
        /// Derived classes can create an instance of a form
        /// derived from <see cref="EmulatorForm" />
        /// in the constructor. This instance is used in the
        /// <see cref="LoadDefaultComponents" />
        /// method override to enable automatic registration of
        /// emulator components managed/wrapped by a UI control.
        /// 
        /// if you are using a UI library of some sort for the
        /// form that prevents the use of EmulatorForm as a base
        /// class the form should implement the
        /// <cref cref="IEmulatorComponentControl" />
        /// </remarks>
        public Form MainForm
        {
            get { return _MainForm; }
            set { this._MainForm = value; }
        }
        private Form _MainForm;
        
        /// <summary>Looks up a platform specific pin number based on its name</summary>
        /// <param name="Name">Name of the pin as defined by the platform</param>
        /// <returns>Pin number for the named pin</returns>
        /// <remarks>
        /// Derived classes MUST override this method. The simplest and most common 
        /// implementation uses an enumeration for all the pins and
        /// <see cref="System.Enum.Parse(System.Type,System.String, System.Boolean)"/>
        /// to parse the Name string to determine the actual CPU pin number. 
        /// 
        ///<para>This method helps to isolate UI control components and config files
        /// from needing to know the exact pin number for a pin and instead can use
        /// a documented human readable symbolic name</para>
        /// </remarks>
        /// <exception cref="ArgumentException">Thrown if the name is not a valid pin name for the platform</exception>
        [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "0#" )]
        public abstract Cpu.Pin GetPinByName(string Name);
        
        /// <summary>Pre-configures default components</summary>
        /// <remarks>
        /// <para>This method is Called by <see cref="CustomEmulator.LoadDefaultComponents()"/>
        /// after calling <see cref="M:Microsoft.SPOT.EmulatorComponents.Emulator.LoadDefaultComponents()"/> 
        /// but before auto registration of the UI components. This allows
        /// derived classes a chance to set up configuration such as the
        /// memory managers, maximum GPIO ports, System Clock frequency,
        /// etc...</para>
        /// <para>This implementation does nothing but is virtual so that
        /// derived clases can implement needed support.</para>
        /// </remarks>
        protected virtual void PreConfigDefaultComponents()
        {
        }

        #region Base class overrides
        /// <summary>Overrides base to provide default components hard wired into this platform</summary>
        /// <remarks>
        /// This method sets up the default components including the GPIO and LCD. The advantage of 
        /// doing this here instead of in an XML file is that the XML can be deleted and or altered
        /// to reflect invalid configuration for the hardware or the emulation. It also allows the LCD
        /// component to automatically take on the dimensions of an LcdControl on the main form via the
        /// automatic component registration. Thus, it is easy to design a new system with different
        /// LCD dimensions. 
        /// </remarks>
        protected override void LoadDefaultComponents()
        {
            base.LoadDefaultComponents();

            PreConfigDefaultComponents();

            // set up the LCD based on the UI item
            if(MainForm != null)
            {
                IEmulatorComponentControl iecc = this.MainForm as IEmulatorComponentControl;
                if(iecc!=null)
                    iecc.RegisterComponents(this);
#if DEBUG
                else
                    System.Diagnostics.Trace.TraceWarning("Main Form does not implement IEmulatorComponentControl, therefore, emulator components will not automatically register!");
#endif
            }
        }

        /// <summary>Initializes the emulator component and starts the UI thread</summary>
        public override void InitializeComponent()
        {
            base.InitializeComponent();
            UIThread = new Thread(new ThreadStart(UIThreadProc));
            UIThread.Start();
        }

        /// <summary>Uninitializes the component and shutsdown the emulator and the application</summary>
        public override void UninitializeComponent()
        {
            base.UninitializeComponent();
            Application.Exit();
        }

        /// <summary>Starts the Emulator</summary>
        /// <param name="args">Command line args string array</param>
        /// <remarks>
        /// if the file "oem.config" exists in the current directory;
        /// this method will add the command line switch "/config:oem.config"
        /// to the comand line args before calling the base implementation. 
        /// </remarks>
        public override void Start(string[] args)
        {
            // If the oem.config file is present add it to the commandline args
            // before starting up the emulator.
            if(File.Exists("oem.config"))
            {
                Array.Resize<string>(ref args, args.Length + 1);
                args[args.Length - 1] = "/config:oem.config";
            }
            base.Start(args);
        }
        #endregion

        #region UI Thread
        private Thread UIThread;
       
        [STAThread]
        private void UIThreadProc()
        {
            // Some initial setup for the WinForm UI
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(MainForm);
            base.Emulator.Stop();
        }
        #endregion
    }
}
